home *** CD-ROM | disk | FTP | other *** search
/ PC Media 4 / PC MEDIA CD04.iso / share / prog / 4dser100 / 4dserial.cpp next >
Encoding:
C/C++ Source or Header  |  1994-08-22  |  31.9 KB  |  1,245 lines

  1. //-----------------------------------------------------------------v1.00----//
  2. // 4D Serial is copyright 1994-1995 by 4D Software / Jeff Jones.  You are   //
  3. // given permission to use these routines under the following conditions.   //
  4. // We see how hard it is to get these routines, so I am being nice enough   //
  5. // to allow you to use them *FREE of charge (note the conditions below).    //
  6. //                                                                          //
  7. // Conditions:                                                              //
  8. //            1) You must place in your software documentation where to     //
  9. //               find our routines, as well as note that you used them.     //
  10. //               If you have no documentation, include the 4D Serial LIB    //
  11. //                 in your archive package, or on disk.                       //
  12. //                                                                          //
  13. //              2) Send us a free, registered copy of the program you wrote   //
  14. //               using these routines.  312-284-2261 is our voice number,   //
  15. //               312-284-7133 is our BBS number.  Our Mailing address is    //
  16. //               P.O. Box 389051, Chicago, Illinois, 60638.                 //
  17. //                                                                          //
  18. //            3) If you are using our routines in a commercial software     //
  19. //               application, you MUST get in touch of us for WRITTEN       //
  20. //               permission of use.  (See #2 for address and phone #'s)     //
  21. // * FREE is a term for general use, commercial use my be required to pay   //
  22. // for research time, etc...                                                //
  23. //                                                                          //
  24. // QUESTIONS???  Call our BBS or write.  NO VOICE CALLS FOR CODE QUESTIONS! //
  25. //                                                                          //
  26. // ERRORS or CODE REVISIONS:  Send them to us via BBS, or call voice.  We   //
  27. // will try to help as much as possible.  DO NOT DISTRIBUTE 4D SERIAL IN    //
  28. // ANY KIND OF MODIFIED FORM!                                               //
  29. //--------------------------------------------------------------------------//
  30.  
  31.     //------------------------------------------------------------------//
  32.     //         * Compile this program with Test Stack Overflow OFF *       //
  33.     //------------------------------------------------------------------//
  34.  
  35. #ifdef __cplusplus
  36.     #define __CPPARGS ...
  37. #else
  38.     #define __CPPARGS
  39. #endif
  40.  
  41. #include <dos.h>
  42. #include <string.h>
  43. #include <alloc.h>
  44. #include <4dserial.h>
  45.  
  46. char *SERIAL_OSName[5] = { "Unknown", "DOS", "OS/2", "DESQview", "Windows" };
  47.  
  48. SERIALINFO        SERIAL;
  49.  
  50.     //------------------------------------------------------------------//
  51.     //         The following functions are local to 4D SERIAL itself       //
  52.     //------------------------------------------------------------------//
  53.  
  54. void interrupt     far (*SERIAL_TimerOldHandler)(__CPPARGS);
  55. void interrupt  far    SERIAL_TimerIntHandler(__CPPARGS);
  56. void                 SERIAL_TimerInitISR(void);
  57. void                 SERIAL_TimerDeInitISR(void);
  58.  
  59. void interrupt     far (*SERIAL_OldHandler)(__CPPARGS);
  60. void interrupt  far    SERIAL_IntHandler(__CPPARGS);
  61. static char         SERIAL_CheckInt(void);
  62. void                 SERIAL_FIFOInit(void);
  63. int                 SERIAL_InitISR(int irqnum);
  64. void                 SERIAL_UnInitISR(void);
  65. void                 SERIAL_InitBuffer(RING *ring, char *address, int length);
  66. void                 SERIAL_PutBuf(RING *ring, char chr);
  67. int                 SERIAL_GetBuf(RING *ring, char *chr);
  68. static char         SERIAL_ComBuffers(char create, int inbufsize, int outbufsize);
  69. void                 SERIAL_SetCommParams(long baudrate, int parity, int databits, int stopbits);
  70. int                  SERIAL_SendChar(char c);
  71. void                 SERIAL_SetDTR(char OnOff);
  72. void                 SERIAL_SetRTS(char OnOff);
  73. int                 SERIAL_CheckRTS(void);
  74. int                 SERIAL_CheckCTS(void);
  75. int                 SERIAL_CarrierDetect(void);
  76. void                 SERIAL_Break(char OnOff);
  77. int                    SERIAL_CharReady(void);
  78.  
  79. int                 FOSSIL_InitializeDriver(void);
  80. int                 FOSSIL_SetPort(long baudrate, int parity, int databits, int stopbits);
  81. void                 FOSSIL_HandshakeOn(void);
  82. void                 FOSSIL_DeInitializeDriver(void);
  83. int                    FOSSIL_SendChar(char c);
  84. void                 FOSSIL_SetDTR(char OnOff);
  85. int                    FOSSIL_CarrierDetect(void);
  86. void                 FOSSIL_Break(char OnOff);
  87. char                FOSSIL_GetChar(void);
  88. int                    FOSSIL_CharReady(void);
  89. void                FOSSIL_CheckErrors(void);
  90. void                FOSSIL_PurgeOutBuf(void);
  91. void                FOSSIL_PurgeInBuf(void);
  92. void                FOSSIL_FlushOutBuf(void);
  93.  
  94. int                 DIGIBOARD_InitializeDriver(void);
  95. int                 DIGIBOARD_SetPort(long baudrate, int parity, int databits, int stopbits);
  96. void                 DIGIBOARD_HandshakeOn(void);
  97. void                 DIGIBOARD_DeInitializeDriver(void);
  98. int                       DIGIBOARD_SendChar(char c);
  99. void                 DIGIBOARD_SetDTR(char OnOff);
  100. int                    DIGIBOARD_CarrierDetect(void);
  101. void                 DIGIBOARD_Break(void);
  102. char                DIGIBOARD_GetChar(void);
  103. int                    DIGIBOARD_CharReady(void);
  104. void                DIGIBOARD_CheckErrors(void);
  105. void                DIGIBOARD_PurgeOutBuf(void);
  106. void                DIGIBOARD_PurgeInBuf(void);
  107. void                DIGIBOARD_FlushOutBuf(void);
  108.  
  109.     //------------------------------------------------------------------//
  110.     //           The following functions are used by you the programmer     //
  111.     //------------------------------------------------------------------//
  112.  
  113. int     SERIAL_OpenPort(char AsyncType, unsigned PortBase, int IRQ, long baudrate, int parity, int databits, int stopbits);
  114. void     SERIAL_ClosePort(void);
  115. int     SERIAL_CheckError(void);
  116. int        SERIAL_TransmitChar(char c);
  117. void     SERIAL_TransmitStr(char *s);
  118. int        SERIAL_ReceiveChar(void);
  119. int     SERIAL_DataReady(void);
  120. void     SERIAL_ToggleDTR(char OnOff);
  121. void     SERIAL_TransmitBreak(void);
  122. int     SERIAL_OnLine(void);
  123. void    SERIAL_PurgeOutBuf(void);
  124. void    SERIAL_PurgeInBuf(void);
  125. void    SERIAL_FlushOutBuf(void);
  126. void     SERIAL_GetOSType(void);
  127. void     SERIAL_GiveSlice(void);
  128. void     SERIAL_TickDelay(long Ticks);
  129. void     SERIAL_SetTimer(int TimerNumber, long Ticks);
  130. long    SERIAL_GetTimer(int TimerNumber);
  131.  
  132.     //------------------------------------------------------------------//
  133.     //            END OF HEADER BLOCK - FUNCTIONS ARE NOW LISTED            //
  134.     //------------------------------------------------------------------//
  135.  
  136. static char SERIAL_CheckInt(void) {
  137.  
  138. unsigned char     intreg,    chr;
  139. int             i;
  140.  
  141.     intreg = inp(SERIAL.PortBase + 2) | 248; // Identify interrupt //
  142.     // The 248 mask out the upper 5 bits //
  143.  
  144.     if (intreg & 1) return(0);      // Nothing pending //
  145.  
  146.     switch(intreg) {
  147.         case 248 :     // Modem status change //
  148.             SERIAL.ModemStatus = inp(SERIAL.PortBase + 6);
  149.             return(1);
  150.         case 250 :    // Transmitter holding register empty //
  151.             SERIAL.LineStatus = inp(SERIAL.PortBase + 5);
  152.             if (!SERIAL_CarrierDetect() || (SERIAL.ModemStatus & 16)) { // CTS is up before sending a character //
  153.                 for (i = 0; (i < SERIAL.MaxSend) && SERIAL.OutRing.Count; i++) {
  154.                     SERIAL_GetBuf(&SERIAL.OutRing, &SERIAL.InChar);
  155.                     outp(SERIAL.PortBase, SERIAL.InChar);
  156.                 }
  157.             }
  158.             return(1);
  159.         case 252 :     // RX data available //
  160.             while (inp(SERIAL.PortBase + 5) & 1 /* Data Ready */) {
  161.                 chr = inp(SERIAL.PortBase);
  162.                 if ((chr == 0x0B) || // Control-K Received //
  163.                     (chr == 0x03))   // Control-C Received //
  164.                     SERIAL.Abort = chr;
  165.                 else
  166.                     SERIAL_PutBuf(&SERIAL.InRing, chr);
  167.             }
  168.  
  169.             return(1);
  170.         case 254 :    // Line status change //
  171.             SERIAL.LineStatus = inp(SERIAL.PortBase + 5);
  172.             if (SERIAL.LineStatus &  2 /* Overrun Error */)
  173.                 SERIAL.Error = SERIAL_OVRRUN_ERROR;
  174.             if (SERIAL.LineStatus &  4 /* Parity Error */)
  175.                 SERIAL.Error = SERIAL_PARITY_ERROR;
  176.             if (SERIAL.LineStatus &  8 /* Frame Error */)
  177.                 SERIAL.Error = SERIAL_FRAME_ERROR;
  178.             if (SERIAL.LineStatus & 16 /* Break Error */)
  179.                 SERIAL.Error = SERIAL_BREAK_ERROR;
  180.             return(1);
  181.     }
  182.     return(0); // Error
  183.  
  184. }
  185.  
  186. void interrupt far SERIAL_IntHandler(__CPPARGS) {
  187.  
  188.     enable();
  189.  
  190.     if (SERIAL_CheckInt() == 0) {   // No interrupt identifiable //
  191.         if (SERIAL.IRQShared) // Determine is the IRQ is shared or not //
  192.             _chain_intr(SERIAL_OldHandler); // Execute the Old Handler //
  193.     }
  194.     else while(SERIAL_CheckInt()); // Process all interrupt events //
  195.  
  196.     if (SERIAL.IRQ > 7)
  197.         outp(0x00A0, 0x0020); // Check for 2nd PIC //
  198.  
  199.     outp(0x0020, 0x0020); // Send End of Interrupt to 1st PIC //
  200.  
  201. }
  202.  
  203. void SERIAL_FIFOInit(void) {
  204.  
  205.     SERIAL.FIFOExists = 0;
  206.     SERIAL.MaxSend = 1;
  207.  
  208.     // If local mode, there's no communication, so no FIFO //
  209.     if (SERIAL.Type == SERIAL_LOCAL) return;
  210.  
  211.     // See if UART is an 8250 (no scratch register) //
  212.     outp(SERIAL.PortBase + 7 /* Scratch Register */, 0x55);
  213.     if (inp(SERIAL.PortBase + 7 /* Scratch Register */) != 0x55)
  214.         return; // No scratch register, it's an 8250 //
  215.  
  216.     // See if the UART has a FIFO buffer //
  217.     outp(SERIAL.PortBase + 2, 0x0F);
  218.  
  219.     if (inp(SERIAL.PortBase + 2)) return;
  220.  
  221.     SERIAL.FIFOExists     = 1;
  222.     SERIAL.MaxSend         = 8;
  223.  
  224.     outp(SERIAL.PortBase + 2, 1 | 2 | 4 | 64) ; // 8 byte trigger level //
  225.  
  226. }
  227.  
  228. int SERIAL_InitISR(int irqnum) {
  229.  
  230. unsigned char     picmask, oldvalue;
  231.  
  232.     SERIAL.IRQ = irqnum;
  233.  
  234.     SERIAL_OldHandler = _dos_getvect(irqnum + 8);
  235.  
  236.     _dos_setvect(irqnum + 8, SERIAL_IntHandler);
  237.  
  238.     // Setup Modem Control Register's bits //
  239.  
  240.     outp(SERIAL.PortBase + 4 /* Modem Control */, 0x0001 | 0x0002 | 0x0004 | 0x0008);
  241.  
  242.     picmask = 1 << (SERIAL.IRQ % 8);
  243.  
  244.     disable();
  245.  
  246.     oldvalue = inp(((SERIAL.IRQ > 7) ? 0x00A0 : 0x0020) + 1); // Read PIC's interrupt enable register //
  247.     outp(((SERIAL.IRQ > 7) ? 0x00A0 : 0x0020) + 1, oldvalue & !picmask);
  248.  
  249.     enable();
  250.  
  251.     SERIAL.IRQShared = !(oldvalue & picmask);
  252.  
  253.     outp(SERIAL.PortBase + 1, 0); // Disable UART interrupts //
  254.  
  255.     SERIAL_FIFOInit();
  256.  
  257.     // Read UART registers to clear them //
  258.     SERIAL.ModemStatus = inp(SERIAL.PortBase + 6);
  259.     SERIAL.LineStatus  = inp(SERIAL.PortBase + 5);
  260.     inp(SERIAL.PortBase);                        // Read any pending chars //
  261.     inp(SERIAL.PortBase + 2);                     // to clear the interrupt //
  262.                                                  // identification reg     //
  263.  
  264.     outp(SERIAL.PortBase + 1, 1 | 2 | 4 | 8);    // Enable UART interrupts //
  265.  
  266.     outp((SERIAL.IRQ > 7) ? 0x00A0 : 0x0020, 0x0020);     // Reset the PIC //
  267.  
  268.     return(1);
  269.  
  270. }
  271.  
  272. void SERIAL_UnInitISR(void) {
  273.  
  274.     if (SERIAL.FIFOExists)
  275.         outp(SERIAL.PortBase + 2, 0x00); //Turn off the FIFO, if ON //
  276.  
  277.     outp(SERIAL.PortBase + 1, 0x00);    // Disable UART interrupts //
  278.     _dos_setvect(SERIAL.IRQ + 8, SERIAL_OldHandler);
  279.  
  280. }
  281.  
  282. void SERIAL_InitBuffer(RING *ring, char *address, int length) {
  283.  
  284.     // Initialize the buffer values //
  285.     ring->Count  = 0;
  286.     ring->Start  = 0;
  287.     ring->Cnext  = 0;
  288.     ring->Buffer = address;
  289.     ring->Size      = length;
  290. }
  291.  
  292. void SERIAL_PutBuf(RING *ring, char chr) {
  293.  
  294.     // Puts a character into the rotating buffer (ring buffer) //
  295.     ring->Buffer[ring->Cnext++] = chr;
  296.  
  297.     if (ring->Count++ >= ring->Size) {  // Overflow Condition? //
  298.         ring->Count--;
  299.  
  300.         if (ring->Start++ >= ring->Size) // Move the starting point //
  301.             ring->Start -= ring->Size;
  302.     }
  303.  
  304.     // Check if we need to wrap to the the beginning of the buffer again //
  305.     if (ring->Cnext >= ring->Size) ring->Cnext -= ring->Size;
  306.  
  307.     if ((!SERIAL.InputHS)&&(SERIAL.InRing.Size-SERIAL.InRing.Count < 2)) {
  308.         SERIAL.InputHS = 1;
  309.         SERIAL_SetRTS(0);
  310.     }
  311. }
  312.  
  313. int SERIAL_GetBuf(RING *ring, char *chr) {
  314.  
  315.     // Retrieve a character from our ring buffer //
  316.     if (ring->Count <= 0) return(0); // Buffer empty - nothing there //
  317.  
  318.     *chr = (char) ring->Buffer[ring->Start++];
  319.     ring->Count--;    // Update amount of retrievable characters //
  320.  
  321.     if (ring->Start >= ring->Size) ring->Start -= ring->Size;
  322.  
  323.     if ((SERIAL.InputHS)&&(SERIAL.InRing.Count < (SERIAL.InRing.Size*.8))) {
  324.         SERIAL.InputHS = 0;
  325.         SERIAL_SetRTS(1);
  326.     }
  327.  
  328.     return(1);
  329. }
  330.  
  331. static char SERIAL_ComBuffers(char create, int inbufsize, int outbufsize) {
  332.  
  333. static char *outbuf;
  334. static char *inbuf;
  335. static char cbmade = 0;
  336.  
  337.     if (create) {    // Create our buffer //
  338.         if (cbmade) return(1);
  339.         if ((outbuf = (char *) malloc(outbufsize)) == NULL) return(0);
  340.  
  341.         if ((inbuf = (char *) malloc(inbufsize)) == NULL) {
  342.             free(outbuf);
  343.             return(0);
  344.         }
  345.  
  346.         SERIAL_InitBuffer(&SERIAL.OutRing, outbuf, outbufsize);
  347.         SERIAL_InitBuffer(&SERIAL.InRing,  inbuf,  inbufsize);
  348.         cbmade = 1;
  349.         return(1);
  350.     }
  351.  
  352.     else {        // Kill a buffer for closing purposes //
  353.         if (cbmade) {
  354.             free(inbuf);
  355.             free(outbuf);
  356.             cbmade = 0;
  357.         }
  358.         return(0);
  359.     }
  360. }
  361.  
  362. void SERIAL_SetCommParams(long baudrate, int parity, int databits, int stopbits) {
  363.  
  364. unsigned int     divisor;
  365. unsigned char     lsb, msb;
  366. unsigned char   parambyte;
  367.  
  368.     divisor = 115200l / baudrate;
  369.     msb = divisor >> 8;
  370.     lsb = (divisor << 8) >> 8;
  371.  
  372.     outp(SERIAL.PortBase + 3, 128 /* DLAB */); // Enable access to the divisor //
  373.                                                // latches by setting the divisor //
  374.                                                // latch access bit int the Line //
  375.                                                // Control Register //
  376.  
  377.     outp(SERIAL.PortBase, lsb); // Least Significant bit of divisor //
  378.     outp(SERIAL.PortBase + 1, msb); // Most significant bit //
  379.  
  380.     parambyte = databits - 5;    // Sets Bits 1 + 2 //
  381.  
  382.     if (stopbits == 2) parambyte |= 4; // LCR stop bits setting //
  383.  
  384.     switch(parity) {
  385.         case 'O' : // Odd Parity //
  386.         case 'o' : parambyte |= 8; // LCR Parity Enable bit //
  387.             break;
  388.         case 'E' : // Even Parity //
  389.         case 'e' : parambyte |= 8; // LCR Parity Enable bit //
  390.                    parambyte |= 16; // LCR Parity Select bit //
  391.             break;
  392.         default  : // No parity is the default if not an 'O' or 'E' //
  393.             break;
  394.     }
  395.  
  396.     outp(SERIAL.PortBase + 3, parambyte);
  397.  
  398. }
  399.  
  400. int SERIAL_SendChar(char c) {
  401.  
  402.     if (SERIAL.OutRing.Count || !(inp(SERIAL.PortBase + 5) & 32 /* THRE */)) {
  403.         if (SERIAL.OutRing.Count >= SERIAL.OutRing.Size)
  404.             return(1); // Buffer is Full, don't add the new char //
  405.         SERIAL_PutBuf(&SERIAL.OutRing, c); // Add char to output buffer //
  406.     }
  407.     else
  408.         outp(SERIAL.PortBase, c);
  409.  
  410.     return(0);
  411. }
  412.  
  413. void SERIAL_SetDTR(char OnOff) {
  414.  
  415. int r;
  416.  
  417.     r = inp(SERIAL.PortBase + 4 /* Modem Control */);
  418.  
  419.     if (OnOff)
  420.         outp(SERIAL.PortBase + 4 /* Modem Control */, r | 0x0001);
  421.     else
  422.         outp(SERIAL.PortBase + 4 /* Modem Control */, r & (~0x0001));
  423. }
  424.  
  425. void SERIAL_SetRTS(char OnOff) {
  426.  
  427. int r;
  428.  
  429.     r = inp(SERIAL.PortBase + 4 /* Modem Control */);
  430.  
  431.     if (OnOff)
  432.         outp(SERIAL.PortBase + 4 /* Modem Control */, r | 0x0002);
  433.     else
  434.         outp(SERIAL.PortBase + 4 /* Modem Control */, r & (~0x0002));
  435. }
  436.  
  437. int SERIAL_CheckRTS(void) { // Returns True is RTS is up //
  438.  
  439.     return(inp(SERIAL.PortBase + 4 /* Modem Control */) & 0x0002);
  440.  
  441. }
  442.  
  443. int SERIAL_CheckCTS(void) { // Returns True is CTS is up //
  444.  
  445.     return(inp(SERIAL.PortBase + 6 /* Modem Control */) & 0x0010);
  446.  
  447. }
  448.  
  449. int SERIAL_CarrierDetect(void) {
  450.  
  451.     if (inp(SERIAL.PortBase + 6) & 128) return(1);
  452.  
  453.     return(0);
  454. }
  455.  
  456. void SERIAL_Break(char OnOff) {
  457.  
  458. int r;
  459.  
  460.     r = inp(SERIAL.PortBase + 3 /* Line Control */);
  461.  
  462.     if (OnOff)
  463.         outp(SERIAL.PortBase + 3 /* Line Control */, r | 0x0040);
  464.     else
  465.         outp(SERIAL.PortBase + 3 /* Line Control */, r & (~0x0040));
  466. }
  467.  
  468. int SERIAL_CharReady(void) {
  469.  
  470.     if (SERIAL.InRing.Count > 0) return(1); // Buffer has a char in it //
  471.  
  472.     return(0);
  473. }
  474.  
  475. int FOSSIL_InitializeDriver(void) {
  476.  
  477. union    REGS     regs;
  478. struct    SREGS    sregs;
  479.  
  480.     regs.h.ah = 0x04;
  481.     regs.x.dx = SERIAL.PortBase;
  482.     int86x(0x14,®s, ®s, &sregs);
  483.     if (regs.x.ax != 0x1954) return(1);
  484.  
  485.     return(0);
  486. }
  487.  
  488. int FOSSIL_SetPort(long baudrate, int parity, int databits, int stopbits) {
  489.  
  490. union    REGS     regs;
  491. int        Set = 0;
  492.  
  493.     switch(baudrate) {
  494.         case   300 : Set = 0x40; break; // 010 (set 7th logical bit to on) //
  495.         case   600 : Set = 0x60; break; // 011                             //
  496.         case  1200 : Set = 0x80; break; // 100                             //
  497.         case  2400 : Set = 0xA0; break; // 101                             //
  498.         case  4800 : Set = 0xC0; break; // 110                             //
  499.         case  9600 : Set = 0xE0; break; // 111                             //
  500.         case 19200 : Set = 0x00; break; // 000                             //
  501.         case 38400 : Set = 0x02; break; // 001                             //
  502.         default    : return(1);
  503.     }
  504.  
  505.     switch(parity) {
  506.         case 'O' :
  507.         case 'o' : Set |= 0x08; break; // 01 (4th logical bit to on)        //
  508.         case 'E' :
  509.         case 'e' : Set |= 0x18; break; // 11 (5th and 4th bits to on)      //
  510.         default  : Set |= 0x00; break; // 00                               //
  511.     }
  512.  
  513.     switch(stopbits) {
  514.         case  1 : Set |= 0x00; break; // 0 (3rd logical bit to off)         //
  515.         default : Set |= 0x04; break; // 1                                 //
  516.     }
  517.  
  518.     switch(databits) {
  519.         case  5 : Set |= 0x00; break; // 00 (bits 2 and 1 off) //
  520.         case  6 : Set |= 0x01; break; // 01                    //
  521.         case  7 : Set |= 0x02; break; // 10                    //
  522.         default : Set |= 0x03; break; // 11                    //
  523.     }
  524.  
  525.     regs.h.ah = 0x00;
  526.     regs.h.al = Set;
  527.     regs.x.dx = SERIAL.PortBase;
  528.     int86(0x14,®s, ®s);
  529.  
  530.     return(0);
  531. }
  532.  
  533. void FOSSIL_Break(char OnOff) {
  534.  
  535. union    REGS     regs;
  536.  
  537.     regs.h.ah = 0x1A; // Transmit, no wait //
  538.     regs.x.dx = SERIAL.PortBase;
  539.     if (OnOff)
  540.         regs.h.al = 0x01; // On //
  541.     else
  542.         regs.h.al = 0x00; // Off //
  543.     int86(0x14,®s, ®s);
  544. }
  545.  
  546. int    FOSSIL_CarrierDetect(void) {
  547.  
  548. union    REGS     regs;
  549.  
  550.     regs.h.ah = 0x03; // Request Status //
  551.     regs.x.dx = SERIAL.PortBase;
  552.     int86(0x14,®s, ®s);
  553.     if (regs.h.al & 128) return(1);
  554.     return(0);
  555. }
  556.  
  557. void FOSSIL_SetDTR(char OnOff) {
  558.  
  559. union    REGS     regs;
  560.  
  561.     regs.h.ah = 0x06;
  562.     regs.x.dx = SERIAL.PortBase;
  563.     if (OnOff)
  564.         regs.h.al = 0x01; // Raise //
  565.     else
  566.         regs.h.al = 0x00; // Lower //
  567.     int86(0x14,®s, ®s);
  568. }
  569.  
  570. void FOSSIL_HandshakeOn(void) {
  571.  
  572. union    REGS     regs;
  573.  
  574.     regs.h.ah = 0x0F; // Transmit, no wait //
  575.     regs.x.dx = SERIAL.PortBase;
  576.     regs.h.al = 242;
  577.     int86(0x14,®s, ®s);
  578. }
  579.  
  580. char FOSSIL_GetChar(void) {
  581.  
  582. union    REGS     regs;
  583.  
  584.     regs.h.ah = 0x02; // Receive, with wait //
  585.     regs.x.dx = SERIAL.PortBase;
  586.     int86(0x14,®s, ®s);
  587.  
  588.     return(regs.h.al);
  589. }
  590.  
  591. int FOSSIL_CharReady(void) {
  592.  
  593. union    REGS     regs;
  594.  
  595.     regs.h.ah = 0x0C; // `PEEK' style char read w/Status of Availability //
  596.     regs.x.dx = SERIAL.PortBase;
  597.     int86(0x14,®s, ®s);
  598.     if (regs.x.ax == 0xFFFF) return(0);
  599.  
  600.     if ((regs.h.al == 0x0B) ||     // Control-K Received //
  601.         (regs.h.al == 0x03)) {     // Control-C Received //
  602.         FOSSIL_GetChar();       // Remove NOW unwanted character //
  603.         SERIAL.Abort = regs.h.al;
  604.     }
  605.     else return(1);
  606.  
  607.     return(0);
  608. }
  609.  
  610. int FOSSIL_SendChar(char c) {
  611.  
  612. union    REGS     regs;
  613.  
  614.     regs.h.ah = 0x0B; // Transmit, no wait //
  615.     regs.x.dx = SERIAL.PortBase;
  616.     regs.h.al = c;
  617.     int86(0x14,®s, ®s);
  618.     if (regs.x.ax == 0x0000) return(1);
  619.  
  620.     return(0);
  621. }
  622.  
  623. void FOSSIL_CheckErrors(void) {
  624.  
  625. union    REGS     regs;
  626.  
  627.     regs.h.ah = 0x03;
  628.     regs.x.dx = SERIAL.PortBase;
  629.     int86(0x14,®s, ®s);
  630.     if (regs.h.ah &  2 /* Overrun Error */)
  631.         SERIAL.Error = SERIAL_OVRRUN_ERROR;
  632. }
  633.  
  634. void FOSSIL_PurgeOutBuf(void) {
  635.  
  636. union    REGS     regs;
  637.  
  638.     regs.h.ah = 0x09;
  639.     regs.x.dx = SERIAL.PortBase;
  640.     int86(0x14,®s, ®s);
  641. }
  642.  
  643. void FOSSIL_PurgeInBuf(void) {
  644.  
  645. union    REGS     regs;
  646.  
  647.     regs.h.ah = 0x0A;
  648.     regs.x.dx = SERIAL.PortBase;
  649.     int86(0x14,®s, ®s);
  650. }
  651.  
  652. void FOSSIL_FlushOutBuf(void) {
  653.  
  654. union    REGS     regs;
  655.  
  656.     regs.h.ah = 0x08;
  657.     regs.x.dx = SERIAL.PortBase;
  658.     int86(0x14,®s, ®s);
  659. }
  660.  
  661. void FOSSIL_DeInitializeDriver(void) {
  662.  
  663. union    REGS     regs;
  664.  
  665.     regs.h.ah = 0x05;
  666.     regs.x.dx = SERIAL.PortBase;
  667.     int86(0x14,®s, ®s);
  668. }
  669.  
  670. int SERIAL_OpenPort(char AsyncType, unsigned PortBase, int IRQ, long baudrate, int parity, int databits, int stopbits) {
  671.  
  672.     memset(&SERIAL,0,sizeof(SERIALINFO)); // Set all data members to 0 //
  673.     SERIAL.PortBase = PortBase;
  674.     SERIAL.Type = AsyncType;
  675.  
  676.     switch(AsyncType) {
  677.         case SERIAL_LOCAL :
  678.             break;
  679.  
  680.         case SERIAL_ASYNC :
  681.             if ((IRQ < 2) || (IRQ > 15) || (!PortBase))    return(1);
  682.  
  683.             SERIAL_SetCommParams(baudrate,parity,databits,stopbits);
  684.             if (!SERIAL_ComBuffers(1, 4096, 2048)) return(2); // 4K input buffer, 2K output buffer
  685.             SERIAL_InitISR(IRQ);
  686.  
  687.             break;
  688.  
  689.         case SERIAL_FOSSIL :
  690.             if ((SERIAL.PortBase > 64)||(SERIAL.PortBase < 0)) return(3);
  691.             if (FOSSIL_InitializeDriver()) return(4);
  692.             if (FOSSIL_SetPort(baudrate,parity,databits,stopbits)) {
  693.                 FOSSIL_DeInitializeDriver();
  694.                 return(5);
  695.             }
  696.             FOSSIL_HandshakeOn();
  697.  
  698.             break;
  699.  
  700.         case SERIAL_DIGIBOARD :
  701.             if ((SERIAL.PortBase > 64)||(SERIAL.PortBase < 0)) return(3);
  702.             if (DIGIBOARD_InitializeDriver()) return(4);
  703.             if (DIGIBOARD_SetPort(baudrate,parity,databits,stopbits)) {
  704.                 DIGIBOARD_DeInitializeDriver();
  705.                 return(5);
  706.             }
  707.             DIGIBOARD_HandshakeOn();
  708.  
  709.             break;
  710.  
  711.         default :
  712.             return(2);
  713.     }
  714.  
  715.     SERIAL_TimerInitISR();
  716.     return(0);
  717. }
  718.  
  719. void SERIAL_ClosePort(void) {
  720.  
  721.     SERIAL_TimerDeInitISR();
  722.  
  723.     switch(SERIAL.Type) {
  724.         case SERIAL_LOCAL :
  725.             break;
  726.  
  727.         case SERIAL_ASYNC :
  728.             SERIAL_UnInitISR(); // Reset Interrupt Vector to original //
  729.             SERIAL_ComBuffers(0, 4096, 2048); // De-Init Ring Buffers //
  730.             break;
  731.  
  732.         case SERIAL_FOSSIL :
  733.             FOSSIL_DeInitializeDriver();
  734.             break;
  735.  
  736.         case SERIAL_DIGIBOARD :
  737.             DIGIBOARD_DeInitializeDriver();
  738.             break;
  739.  
  740.         default    :
  741.             break;
  742.     }
  743. }
  744.  
  745. int    SERIAL_TransmitChar(char c) {
  746.  
  747.     switch(SERIAL.Type) {
  748.         case SERIAL_LOCAL     : return(0);
  749.         case SERIAL_ASYNC     : return(SERIAL_SendChar(c));
  750.         case SERIAL_FOSSIL    : return(FOSSIL_SendChar(c));
  751.         case SERIAL_DIGIBOARD : return(DIGIBOARD_SendChar(c));
  752.     }
  753.     return(0);
  754. }
  755.  
  756. int SERIAL_DataReady(void) {
  757.  
  758.     switch(SERIAL.Type) {
  759.         case SERIAL_LOCAL     : return(0);
  760.         case SERIAL_ASYNC     : return(SERIAL_CharReady());
  761.         case SERIAL_FOSSIL    : return(FOSSIL_CharReady());
  762.         case SERIAL_DIGIBOARD : return(DIGIBOARD_CharReady());
  763.     }
  764.     return(0);
  765. }
  766.  
  767. void SERIAL_ToggleDTR(char OnOff) {
  768.  
  769.     switch(SERIAL.Type) {
  770.         case SERIAL_LOCAL     : return;
  771.         case SERIAL_ASYNC     : SERIAL_SetDTR(OnOff); break;
  772.         case SERIAL_FOSSIL    : FOSSIL_SetDTR(OnOff); break;
  773.         case SERIAL_DIGIBOARD :    DIGIBOARD_SetDTR(OnOff); break;
  774.     }
  775. }
  776.  
  777. int SERIAL_OnLine(void) {
  778.  
  779.     switch(SERIAL.Type) {
  780.         case SERIAL_LOCAL     : return(1);
  781.         case SERIAL_ASYNC     : return(SERIAL_CarrierDetect());
  782.         case SERIAL_FOSSIL    : return(FOSSIL_CarrierDetect());
  783.         case SERIAL_DIGIBOARD : return(DIGIBOARD_CarrierDetect());
  784.     }
  785.     return(0);
  786. }
  787.  
  788. int SERIAL_CheckError(void) {
  789.  
  790.     switch(SERIAL.Type) {
  791.         case SERIAL_LOCAL     : break;
  792.         case SERIAL_ASYNC     : break;
  793.         case SERIAL_FOSSIL    :    FOSSIL_CheckErrors(); break;
  794.         case SERIAL_DIGIBOARD :    DIGIBOARD_CheckErrors(); break;
  795.     }
  796.     return(SERIAL.Error);
  797. }
  798.  
  799. int    SERIAL_ReceiveChar(void) { // No WAIT function //
  800.  
  801. char    c;
  802.  
  803.     switch(SERIAL.Type) {
  804.         case SERIAL_LOCAL     :    break;
  805.  
  806.         case SERIAL_ASYNC     :    if (SERIAL_GetBuf(&SERIAL.InRing, &c))
  807.                                     return(c);
  808.                                 break;
  809.  
  810.         case SERIAL_FOSSIL    : if (FOSSIL_CharReady())
  811.                                     return(FOSSIL_GetChar());
  812.                                 break;
  813.  
  814.         case SERIAL_DIGIBOARD : if (DIGIBOARD_CharReady())
  815.                                     return(DIGIBOARD_GetChar());
  816.                                 break;
  817.     }
  818.     return(0);
  819. }
  820.  
  821. void SERIAL_TransmitStr(char *s) {
  822.  
  823.     switch(SERIAL.Type) {
  824.         case SERIAL_LOCAL     : break;
  825.         case SERIAL_ASYNC     : while(*s) SERIAL_SendChar(*s++); break;
  826.         case SERIAL_FOSSIL    : while(*s) FOSSIL_SendChar(*s++); break;
  827.         case SERIAL_DIGIBOARD : while(*s) DIGIBOARD_SendChar(*s++); break;
  828.     }
  829.     return;
  830. }
  831.  
  832. void SERIAL_PurgeOutBuf(void) {
  833.  
  834.     switch(SERIAL.Type) {
  835.         case SERIAL_LOCAL     :    break;
  836.  
  837.         case SERIAL_ASYNC     : // RE-Initialize the buffer values //
  838.                                 SERIAL.OutRing.Count  = 0;
  839.                                 SERIAL.OutRing.Start  = 0;
  840.                                 SERIAL.OutRing.Cnext  = 0;
  841.                                 break;
  842.  
  843.         case SERIAL_FOSSIL    : FOSSIL_PurgeOutBuf(); break;
  844.  
  845.         case SERIAL_DIGIBOARD : DIGIBOARD_PurgeOutBuf(); break;
  846.     }
  847.     return;
  848. }
  849.  
  850. void SERIAL_PurgeInBuf(void) {
  851.  
  852.     switch(SERIAL.Type) {
  853.         case SERIAL_LOCAL     :    break;
  854.  
  855.         case SERIAL_ASYNC     : // RE-Initialize the buffer values //
  856.                                 SERIAL.InRing.Count  = 0;
  857.                                 SERIAL.InRing.Start  = 0;
  858.                                 SERIAL.InRing.Cnext  = 0;
  859.                                 break;
  860.  
  861.         case SERIAL_FOSSIL    : FOSSIL_PurgeInBuf(); break;
  862.  
  863.         case SERIAL_DIGIBOARD : DIGIBOARD_PurgeInBuf(); break;
  864.     }
  865.     return;
  866. }
  867.  
  868. void SERIAL_FlushOutBuf(void) {
  869.  
  870.     switch(SERIAL.Type) {
  871.         case SERIAL_LOCAL     :    break;
  872.  
  873.         case SERIAL_ASYNC     :    while(SERIAL_CarrierDetect() && SERIAL.OutRing.Count);
  874.                                 break;
  875.  
  876.         case SERIAL_FOSSIL    : FOSSIL_FlushOutBuf(); break;
  877.  
  878.         case SERIAL_DIGIBOARD : DIGIBOARD_FlushOutBuf(); break;
  879.     }
  880.     return;
  881. }
  882.  
  883. void SERIAL_TransmitBreak(void) {
  884.  
  885.     // The 5 ticks for delay we use is slightly more than 250 ms;  It's as //
  886.     // close as we can get while giving up time slices.                    //
  887.  
  888.     switch(SERIAL.Type) {
  889.         case SERIAL_LOCAL     :    break;
  890.  
  891.         case SERIAL_ASYNC     : SERIAL_Break(1);
  892.                                 SERIAL_TickDelay(5);
  893.                                 SERIAL_Break(0);
  894.                                 break;
  895.  
  896.         case SERIAL_FOSSIL    : FOSSIL_Break(1);
  897.                                 SERIAL_TickDelay(5);
  898.                                 FOSSIL_Break(0);
  899.                                 break;
  900.  
  901.         case SERIAL_DIGIBOARD : DIGIBOARD_Break(); break;
  902.     }
  903.     return;
  904. }
  905.  
  906. int DIGIBOARD_InitializeDriver(void) {
  907.  
  908. union    REGS     regs;
  909. struct     SREGS     sregs;
  910.  
  911.     regs.h.ah = 0xF4;
  912.     regs.h.al = 0x08;
  913.     regs.x.dx = SERIAL.PortBase;
  914.     int86(0x14,®s, ®s);
  915.     if (regs.x.ax != 0x0000) return(1);
  916.  
  917.     regs.h.ah = 0x0D;                    // set ah = 0Dh
  918.     regs.h.al = 0x00;                     // To clear it...
  919.     regs.x.dx = SERIAL.PortBase;        // set channel number
  920.     int86x(0x14,®s,®s,&sregs);    // make INT 14h call
  921.  
  922.     SERIAL.DataReady =
  923.         (unsigned char far *)MK_FP(sregs.es,regs.x.bx); // far pointer to flag
  924.  
  925.     return(0);
  926. }
  927.  
  928. int    DIGIBOARD_SetPort(long baudrate, int parity, int databits, int stopbits) {
  929.  
  930. union    REGS     regs;
  931.  
  932.     switch(baudrate) {
  933.         case     50 : regs.h.cl = 0x0D; break;
  934.         case     75 : regs.h.cl = 0x0E; break;
  935.         case    110 : regs.h.cl = 0x00; break;
  936.         case    134 : regs.h.cl = 0x0F; break;
  937.         case    150 : regs.h.cl = 0x01; break;
  938.         case    200 : regs.h.cl = 0x10; break;
  939.         case    300 : regs.h.cl = 0x02; break;
  940.         case    600 : regs.h.cl = 0x03; break;
  941.         case   1200 : regs.h.cl = 0x04; break;
  942.         case   1800 : regs.h.cl = 0x11; break;
  943.         case   2400 : regs.h.cl = 0x05; break;
  944.         case   4800 : regs.h.cl = 0x06; break;
  945.         case   9600 : regs.h.cl = 0x07; break;
  946.         case  19200 : regs.h.cl = 0x08; break;
  947.         case  38400 : regs.h.cl = 0x09; break;
  948.         case  57600 : regs.h.cl = 0x0A; break;
  949.         case  76800 : regs.h.cl = 0x0B; break;
  950.         case 115200 : regs.h.cl = 0x0C; break;
  951.         default    : return(1);
  952.     }
  953.  
  954.     switch(parity) {
  955.         case 'O' :
  956.         case 'o' : regs.h.bh = 0x01; break;
  957.         case 'E' :
  958.         case 'e' : regs.h.bh = 0x02; break;
  959.         default  : regs.h.bh = 0x00; break; // None //
  960.     }
  961.  
  962.     switch(stopbits) {
  963.         case  1 : regs.h.bl = 0x00; break; // 1 Stop Bit //
  964.         default : regs.h.bl = 0x01; break; // Default to two //
  965.     }
  966.  
  967.     switch(databits) {
  968.         case  5 : regs.h.ch = 0x00; break;
  969.         case  6 : regs.h.ch = 0x01; break;
  970.         case  7 : regs.h.ch = 0x02; break;
  971.         default : regs.h.ch = 0x03; break; // Default 8 bits //
  972.     }
  973.  
  974.     regs.h.ah = 0x04;
  975.     regs.h.al = 0x00;
  976.     regs.x.dx = SERIAL.PortBase;
  977.     int86(0x14,®s, ®s);
  978.  
  979.     return(0);
  980. }
  981.  
  982. void DIGIBOARD_SetDTR(char OnOff) {
  983.  
  984. union    REGS     regs;
  985.  
  986.     regs.h.ah = 0x05;
  987.     regs.h.al = 0x00; // Read //
  988.     regs.x.dx = SERIAL.PortBase;
  989.     int86(0x14,®s, ®s);
  990.  
  991.     regs.h.al = 0x01; // Write //
  992.     if (OnOff)
  993.         regs.h.bl |= 0x01; // Raise //
  994.     else
  995.         regs.h.bl &= ~0x01; // Lower //
  996.     int86(0x14,®s, ®s);
  997. }
  998.  
  999. int    DIGIBOARD_CarrierDetect(void) {
  1000.  
  1001. union    REGS     regs;
  1002.  
  1003.     regs.h.ah = 0x03; // Request Status //
  1004.     regs.x.dx = SERIAL.PortBase;
  1005.     int86(0x14,®s, ®s);
  1006.     if (regs.h.al & 128) return(1);
  1007.     return(0);
  1008. }
  1009.  
  1010. void DIGIBOARD_HandshakeOn(void) {
  1011.  
  1012. union    REGS     regs;
  1013.  
  1014.     regs.h.ah = 0x1E; // Transmit, no wait //
  1015.     regs.x.dx = SERIAL.PortBase;
  1016.     regs.h.bh = 0x00;
  1017.     regs.h.bl = 0x0A;
  1018.     int86(0x14,®s, ®s);
  1019. }
  1020.  
  1021. void DIGIBOARD_Break(void) {
  1022.  
  1023. union    REGS     regs;
  1024.  
  1025.     regs.h.ah = 0x07; // Transmit, no wait //
  1026.     regs.h.al = 0x00;
  1027.     regs.x.dx = SERIAL.PortBase;
  1028.     int86(0x14,®s, ®s);
  1029. }
  1030.  
  1031. int    DIGIBOARD_CharReady(void) {
  1032.  
  1033. union    REGS     regs;
  1034.  
  1035.     if (*SERIAL.DataReady != 0xFF) return(0); // No char ready //
  1036.  
  1037.     regs.h.ah = 0x14; // `PEEK' style char read //
  1038.     regs.x.dx = SERIAL.PortBase;
  1039.     int86(0x14,®s, ®s);
  1040.  
  1041.     if ((regs.h.al == 0x0B) ||     // Control-K Received //
  1042.         (regs.h.al == 0x03)) {     // Control-C Received //
  1043.         DIGIBOARD_GetChar();      // Remove NOW unwanted character //
  1044.         SERIAL.Abort = regs.h.al;
  1045.     }
  1046.     else return(1);
  1047.  
  1048.     return(0);
  1049. }
  1050.  
  1051. void DIGIBOARD_CheckErrors(void) {
  1052.  
  1053. union    REGS     regs;
  1054.  
  1055.     regs.h.ah = 0x08; // Alternate status check //
  1056.     regs.x.dx = SERIAL.PortBase;
  1057.     int86(0x14,®s, ®s);
  1058.  
  1059.     if (regs.h.ah &  2 /* Overrun Error */)
  1060.         SERIAL.Error = SERIAL_OVRRUN_ERROR;
  1061.     if (regs.h.ah &  4 /* Parity Error */)
  1062.         SERIAL.Error = SERIAL_PARITY_ERROR;
  1063.     if (regs.h.ah &  8 /* Frame Error */)
  1064.         SERIAL.Error = SERIAL_FRAME_ERROR;
  1065.     if (regs.h.ah & 16 /* Break Error */)
  1066.         SERIAL.Error = SERIAL_BREAK_ERROR;
  1067. }
  1068.  
  1069. char DIGIBOARD_GetChar(void) {
  1070.  
  1071. union    REGS     regs;
  1072.  
  1073.     do {
  1074.         regs.h.ah = 0x02; // Receive, with 2 second wait //
  1075.         regs.x.dx = SERIAL.PortBase;
  1076.         int86(0x14,®s, ®s);
  1077.     } while (regs.h.ah & 128); // Make this a WAIT style function, like FOSSIL
  1078.  
  1079.     return(regs.h.al);
  1080. }
  1081.  
  1082. int    DIGIBOARD_SendChar(char c) {
  1083.  
  1084. union    REGS     regs;
  1085.  
  1086.     regs.h.ah = 0x01; // Transmit, no wait //
  1087.     regs.x.dx = SERIAL.PortBase;
  1088.     regs.h.al = c;
  1089.     int86(0x14,®s, ®s);
  1090.     if (regs.h.ah & 128) return(1); // Buffer is full - Char not sent! //
  1091.  
  1092.     return(0); // All's well in the transmit or 'c' //
  1093. }
  1094.  
  1095. void DIGIBOARD_PurgeOutBuf(void) {
  1096.  
  1097. union    REGS     regs;
  1098.  
  1099.     regs.h.ah = 0x11; // FLUSH - not PURGE, as DIGI Driver has no purge interrupt //
  1100.     regs.x.dx = SERIAL.PortBase;
  1101.     int86(0x14,®s, ®s);
  1102. }
  1103.  
  1104. void DIGIBOARD_FlushOutBuf(void) {
  1105.  
  1106. union    REGS     regs;
  1107.  
  1108.     regs.h.ah = 0x11;
  1109.     regs.x.dx = SERIAL.PortBase;
  1110.     int86(0x14,®s, ®s);
  1111. }
  1112.  
  1113. void DIGIBOARD_PurgeInBuf(void) {
  1114.  
  1115. union    REGS     regs;
  1116.  
  1117.     while(DIGIBOARD_CharReady()) {
  1118.         regs.h.ah = 0xFC;
  1119.         regs.x.dx = SERIAL.PortBase;
  1120.         int86(0x14,®s, ®s);
  1121.     }
  1122. }
  1123.  
  1124. void DIGIBOARD_DeInitializeDriver(void) {
  1125.  
  1126.     // Nothing to do here....   But, I'll keep the function BLANK
  1127.     // here for future ease of expansion in the DIGI drivers...
  1128.  
  1129. }
  1130.  
  1131. void SERIAL_GetOSType(void) {
  1132.  
  1133. union     REGS t_regs;
  1134. int     ostype, maj, min;
  1135.  
  1136.     ostype = 0;
  1137.  
  1138.     // test for DOS or OS/2 //
  1139.  
  1140.     if (_osmajor < 20)
  1141.         ostype = ostype | 0x01; // DOS
  1142.     else
  1143.         ostype = ostype | 0x02; // OS2
  1144.  
  1145.     // test for Windows //
  1146.  
  1147.     t_regs.x.ax = 0x1600 ;
  1148.     int86(0x2F, &t_regs, &t_regs);
  1149.  
  1150.     if (t_regs.h.al != 0x00)
  1151.         ostype = ostype | 0x08; // Windows
  1152.  
  1153.     // Test for DESQview //
  1154.  
  1155.     t_regs.x.cx = 0x4445;
  1156.     t_regs.x.dx = 0x5351;
  1157.     t_regs.x.ax = 0x2B01;
  1158.  
  1159.     intdos(&t_regs, &t_regs);
  1160.     if (t_regs.h.al != 0xFF)
  1161.         ostype = ostype | 0x04; // DV
  1162.  
  1163.     if (ostype & 0x01)
  1164.         SERIAL.OSType = 1; // DOS
  1165.  
  1166.     if (ostype & 0x08)
  1167.         SERIAL.OSType = 4; // Windows
  1168.  
  1169.     if (ostype & 0x04)
  1170.         SERIAL.OSType = 3; // DV
  1171.  
  1172.     if (ostype & 0x02)
  1173.         SERIAL.OSType = 2; // OS2
  1174.  
  1175.     return;
  1176. }
  1177.  
  1178. void SERIAL_GiveSlice(void) {
  1179.  
  1180. union REGS t_regs;
  1181.  
  1182.     if (!SERIAL.OSType) SERIAL_GetOSType();
  1183.  
  1184.     switch (SERIAL.OSType) {
  1185.         case 1 : // DOS
  1186.         case 4 : // Windows
  1187.             t_regs.x.ax = 0x1680;
  1188.             int86(0x2F,&t_regs,&t_regs);
  1189.             break;
  1190.  
  1191.         case 2 : // OS2
  1192.             int86(0x28,&t_regs,&t_regs);
  1193.             break;
  1194.  
  1195.         case 3 : // DV
  1196.             t_regs.x.ax = 0x1000;
  1197.             int86(0x15,&t_regs,&t_regs);
  1198.             break;
  1199.     }
  1200. }
  1201.  
  1202. void interrupt far SERIAL_TimerIntHandler(__CPPARGS) {
  1203.  
  1204. register int i = 0;
  1205.  
  1206.     while(i < 10) SERIAL.Timers[i++]--;
  1207.  
  1208.     // Execute the Old Handler in case it's chained from another program //
  1209.     _chain_intr(SERIAL_TimerOldHandler);
  1210.  
  1211.     return;
  1212. }
  1213.  
  1214. void SERIAL_TimerInitISR(void) {
  1215.  
  1216.     SERIAL_TimerOldHandler = _dos_getvect(0x1C);
  1217.  
  1218.     _dos_setvect(0x1C, SERIAL_TimerIntHandler);
  1219. }
  1220.  
  1221. void SERIAL_TimerDeInitISR(void) {
  1222.  
  1223.     _dos_setvect(0x1C, SERIAL_TimerOldHandler); // Reset the interrupt vector upon exit
  1224. }
  1225.  
  1226. void SERIAL_SetTimer(int TimerNumber, long Ticks) {
  1227.  
  1228.     if ((TimerNumber < 0) || (TimerNumber > 9)) return;
  1229.  
  1230.     SERIAL.Timers[TimerNumber] = Ticks;
  1231. }
  1232.  
  1233. long SERIAL_GetTimer(int TimerNumber) {
  1234.  
  1235.     if ((TimerNumber < 0) || (TimerNumber > 9)) return(-999999999L);
  1236.  
  1237.     return(SERIAL.Timers[TimerNumber]);
  1238. }
  1239.  
  1240. void SERIAL_TickDelay(long Ticks) {
  1241.  
  1242.     SERIAL_SetTimer(9,Ticks);
  1243.     while (SERIAL_GetTimer(9) > 0)
  1244.         SERIAL_GiveSlice();
  1245. }